﻿using System;
using System.Collections.Generic;
using MongoDB.Interface;
using MongoDB.Driver;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using ComTools.Helpers;

namespace MongoDB.Implement
{
	/// <summary>
	/// 该类实现了基本的数据库交互
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class DBHelper<T> : IDBHelper<T> where T : new()
	{
		private MongoDBConfig _dbConfig;
		private MongoClient client = null;
		private IMongoCollection<T> collection = null;

		/// <summary>
		///where T : new() 
		/// </summary>
		public DBHelper() { }

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="config">配置对象</param>
		public DBHelper(MongoDBConfig config)
		{
			var colName = AttributesAssemblyHelper.GetClassAttributes<DescriptionAttribute>(new T()).FirstOrDefault().Description;
			this.DBConfig = config;
			collection = GetCollection(colName);
		}

		/// <summary>
		/// 获取或设置数据库配置
		/// </summary>
		public MongoDBConfig DBConfig
		{
			get
			{
				return _dbConfig;
			}
			set
			{
				_dbConfig = value;
				client = new MongoClient(value.ConnectionString);
			}
		}

		/// <summary>
		/// 获取集合
		/// </summary>
		/// <typeparam name="T">集合对应的类型</typeparam>
		/// <param name="collectionName">集合名称</param>
		/// <returns>集合对象</returns>
		public IMongoCollection<T> GetCollection(string collectionName)
		{
			return client.GetDatabase(_dbConfig.DataBase).GetCollection<T>(collectionName);

		}

		/// <summary>
		/// 根据一个表示来查询单个匹配的数据
		/// </summary>
		/// <typeparam name="T">查询结果的类型</typeparam>
		/// <typeparam name="TField">表示表达式中要获取的对应字段的类型</typeparam>
		/// <param name="fieldExpress">匹配字段的表达式</param>
		/// <param name="value">匹配的值</param>
		/// <returns>查询结果</returns>
		public T FindOne<TField>(Expression<Func<T, TField>> fieldExpress, TField value)
		{
			try
			{
				var equal = Builders<T>.Filter.Eq(fieldExpress, value);
				return collection.FindAsync<T>(equal).GetAwaiter().GetResult().FirstOrDefault();
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// 根据表达式查询数据
		/// </summary>
		/// <typeparam name="T">查询的数据类型</typeparam>
		/// <param name="express">表达式</param>
		/// <returns>查询结果</returns>
		public IList<T> FindDataByExpress(Expression<Func<T, bool>> express)
		{
			try
			{
				return collection.AsQueryable().Where(express).ToList<T>();
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// 根据表达式查询排序数据
		/// </summary>
		/// <param name="express"></param>
		/// <param name="orderBy">排序表达式</param>
		/// <param name="sort">1 ASC 2 DESC</param>
		/// <returns></returns>
		public IList<T> FindOrderDataByExpress(Expression<Func<T, bool>> express, Expression<Func<T, object>> orderBy, int sort)
		{
			try
			{
				if (sort == 1)
				{
					//var result= collection.Find(express).SortBy(orderBy).ToList<T>();
					return collection.Find(express).SortBy(orderBy).ToList<T>();
				}
				else
				{
					return collection.Find(express).SortByDescending(orderBy).ToList<T>();
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// 获取所有
		/// </summary>
		/// <returns></returns>
		public IList<T> FindAll()
		{
			try
			{
				return collection.AsQueryable().ToList<T>();
			}
			catch (Exception ex)
			{

				throw ex;
			}
		}


		/// <summary>
		/// 插入自增列
		/// </summary>
		/// <typeparam name="TConditionField"></typeparam>
		/// <typeparam name="TSetField"></typeparam>
		/// <param name="conditionExpress"></param>
		/// <param name="conditionValue"></param>
		/// <param name="setExpress"></param>
		/// <param name="setValue"></param>
		/// <returns></returns>
		public T InsertNextSequence<TConditionField, TSetField>(Expression<Func<T, TConditionField>> conditionExpress, TConditionField conditionValue,
																Expression<Func<T, int>> setExpress,
																Func<T, T> action)
		{
			try
			{
				var options = new FindOneAndUpdateOptions<T, T>() { IsUpsert = true };
				var filter = Builders<T>.Filter.Eq(conditionExpress, conditionValue);
				var update = Builders<T>.Update.Inc(setExpress, 1);
				return action(collection.FindOneAndUpdate<T>(filter, update, options));
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}


		/// <summary>
		/// 插入一条数据
		/// </summary>
		/// <typeparam name="T">数据类型</typeparam>
		/// <param name="t">数据对象</param>
		/// <returns>数据对象</returns>
		public T InsertData(T t)
		{
			try
			{
				collection.InsertOne(t);
				return t;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// 插入多条数据
		/// </summary>
		/// <param name="t"></param>
		/// <returns></returns>
		public List<T> InsertManyData(List<T> t)
		{
			try
			{
				collection.InsertMany(t);
				return t;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// 更新数据库
		/// </summary>
		/// <typeparam name="TConditionField">条件类型</typeparam>
		/// <typeparam name="TSetField">更新类型</typeparam>
		/// <param name="conditionExpress">条件表达式</param>
		/// <param name="conditionValue">条件表达式值</param>
		/// <param name="setExpress">更新字段表达式</param>
		/// <param name="setValue">更新字段值</param>
		/// <returns></returns>
		public long UpdateMany<TConditionField, TSetField>(Expression<Func<T, TConditionField>> conditionExpress, TConditionField conditionValue, Expression<Func<T, TSetField>> setExpress, TSetField setValue)
		{
			try
			{
				var filter = Builders<T>.Filter.Eq(conditionExpress, conditionValue);
				var update = Builders<T>.Update.Set(setExpress, setValue);
				return collection.UpdateMany(filter, update).ModifiedCount;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// 删除多条数据
		/// </summary>
		/// <typeparam name="T">数据类型</typeparam>
		/// <param name="fieldExpress">匹配字段的表达式</param>        
		/// <returns>执行结果</returns>
		public long DeleteMany(Expression<Func<T, bool>> fieldExpress)
		{
			try
			{
				return collection.DeleteMany<T>(fieldExpress).DeletedCount;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		/// <summary>
		/// 删除单条数据
		/// </summary>
		/// <typeparam name="T">数据类型</typeparam>
		/// <param name="fieldExpress">匹配数据的表达式</param>        
		/// <returns>执行结果</returns>
		public bool DeleteOne(Expression<Func<T, bool>> fieldExpress)
		{
			try
			{
				return collection.DeleteOne<T>(fieldExpress).DeletedCount > 0;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}
	}
}
